﻿using Microsoft.AspNetCore.App.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;

namespace Microsoft.AspNetCore.App
{
    public class WebApplication : IApplicationBuilder
    {
        private readonly IApplicationBuilder _applicationBuilder;

        public IWebHostEnvironment Environment => Services.GetRequiredService<IWebHostEnvironment>();

        IServiceProvider IApplicationBuilder.ApplicationServices => _applicationBuilder.ApplicationServices;

        public IServiceProvider Services { get; }

        public WebApplication(IServiceProvider services)
        {
            Services = services;
            _applicationBuilder = new ApplicationBuilder(services);
        }

     
        RequestDelegate IApplicationBuilder.Build()
        {
            return _applicationBuilder.Build();
        }

        public void Use(Func<RequestDelegate, RequestDelegate> middleware)
        {
            _applicationBuilder.Use(middleware);
        }

        public void Run(string url = "http://127.0.0.1:8080")
        {
            var kestrel = ActivatorUtilities.CreateInstance<Kestrel>(Services, _applicationBuilder);
            kestrel.Start(url);
            Logging(url);
            var taskCompletionSource = new TaskCompletionSource();
            taskCompletionSource.Task.GetAwaiter().GetResult();
        }
        public static WebApplicationBuilder CreateBuilder(string[] args)
        {
            //构建配置
            var configurationManager = new ConfigurationManager();
            var environment = ConfigureConfiguration(configurationManager, args);
            //构建容器
            var services = new ServiceCollection();
            //构建日志
            var logging = new LoggingBuilder(services);
            ConfigureLogging(logging, configurationManager);
            //构建服务
            ConfigureServices(services, environment, configurationManager);
            return new WebApplicationBuilder(
                logging,
                services,
                environment,
                configurationManager);
        }
        private static void ConfigureLogging(ILoggingBuilder builder, IConfiguration configuration)
        {
            builder.AddConsole();
            builder.AddDebug();
            builder.AddConfiguration(configuration.GetSection("Logging"));
        }
        private static IWebHostEnvironment ConfigureConfiguration(ConfigurationManager configuration, string[] args)
        {
            configuration.AddCommandLine(args);
            configuration.AddEnvironmentVariables("ASPNETCORE_");
            configuration.SetBasePath(Directory.GetCurrentDirectory());
            configuration.AddJsonFile("appsettings.json", false, true);
            //构建环境
            var environment = new WebHostEnvironment(configuration["Environment"] ?? "Production");
            configuration.AddJsonFile($"appsettings.{environment.EnvironmentName}.json", true, true);
            return environment;
        }
        private static void ConfigureServices(IServiceCollection builder, IWebHostEnvironment environment, IConfiguration configuration)
        {
            //注册路由
            builder.AddRouting();
            builder.AddLogging();
            builder.AddOptions();
            builder.AddSingleton(environment);
            builder.AddSingleton(configuration);
        }
        private void Logging(string url)
        {
            var loggerFactory = Services.GetRequiredService<ILoggerFactory>();
            var logger = loggerFactory.CreateLogger("Microsoft.Hosting.Lifetime");
            logger.LogInformation("Now listening on: {0}", url);
            logger.LogInformation("Application started. Press Ctrl+C to shut down.");
            logger.LogInformation("Hosting environment: {0}", Environment.EnvironmentName);
        }
        class LoggingBuilder : ILoggingBuilder
        {
            public IServiceCollection Services { get; }

            public LoggingBuilder(IServiceCollection services)
            {
                Services = services;
            }
        }
    }
}
